package com.acheli.rideable.entites;

import com.acheli.ACHeli;
import com.acheli.registry.config.CustomDataBus;
import com.acheli.registry.factories.ACHFactories;
import com.acheli.registry.network.ACHeliPacketType;
import com.acheli.registry.network.ICustomSyncable;
import com.acheli.registry.resource.DynamicResourcePack;
import com.acheli.rideable.factory.ACHeliEntitiesFactory;
import com.acheli.rideable.factory.SafetyFactoryProvider;
import com.acheli.rideable.functionLathes.ComponentFL;
import com.acheli.rideable.functionLathes.RideableFL;
import com.acheli.rideable.functionLathes.component.SeatFL;
import com.acheli.rideable.functionLathes.component.compile.JSUtils;
import com.acheli.utils.rotate.RotateWith;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.joml.Quaternionf;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import software.bernie.geckolib.core.animatable.GeoAnimatable;
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.core.animation.AnimatableManager;
import software.bernie.geckolib.util.GeckoLibUtil;

import java.nio.file.Files;

import static com.acheli.ACHeli.MODID;

public class RideableEntity extends Entity implements ICustomSyncable, GeoAnimatable {
    public ACHeliEntitiesFactory<RideableEntity, RideableFL> factory;
    private boolean renderInitiated = false;
    private boolean haveSetup = false;
    private final RideableEntity thisRideable = this;
    private static final EntityDataAccessor<String> factoryName = SynchedEntityData.defineId(RideableEntity.class, EntityDataSerializers.STRING);
    public final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
    public RideableEntity(EntityType<?> entityType, Level level, ACHeliEntitiesFactory<RideableEntity, RideableFL> factory) {
        super(entityType, level);
            this.factory = factory;
            doFactory(factoryNotNull -> factoryNotNull.getProductFunction().INIT());

    }
    public RideableEntity(EntityType<?> entityType, Level level) {
        super(entityType, level);
    }

    public void setUp(boolean isReloading) { //通过历史数据恢复实体
        String get = this.entityData.get(factoryName);
        if (! get.isEmpty()) {
            ACHeliEntitiesFactory<?,?> f = ACHFactories.getFactoryFromMap(get, this);
            this.factory = (ACHeliEntitiesFactory<RideableEntity, RideableFL>) f;
            if (factory == null) {
                this.factory = ACHFactories.getGsonEntitiesFactory(
                        get, this, ACHeli.GsonEntitiesConfigRegisterMap.get(get));
            }
            if (factory != null ) {
                factory.getProductFunction().INIT();
                haveSetup = true;
            }
//            else {
//                kill();
//            }

        }
    }
    public void setUp(String factoryName) {
        ACHeliEntitiesFactory<?,?> f = ACHFactories.getFactoryFromMap(factoryName, this);
        this.factory = (ACHeliEntitiesFactory<RideableEntity, RideableFL>) f;
        if (factory == null) {
            this.factory = ACHFactories.getGsonEntitiesFactory(
                    factoryName, this, ACHeli.GsonEntitiesConfigRegisterMap.get(factoryName));
        }
        factory.getProductFunction().INIT();
        this.entityData.set(RideableEntity.factoryName, factoryName);
        haveSetup = true;
    }

    public boolean doFactory(SafetyFactoryProvider<ACHeliEntitiesFactory<RideableEntity, RideableFL>> factoryProvider) {
        boolean notNull = factory != null;
        if (notNull) {
            factoryProvider.getFct(factory);
        }
        return notNull;
    }

    @Override
    public boolean shouldRenderAtSqrDistance(double distance) {
        doFactory(factoryNotNull -> factoryNotNull.getProductFunction().renderDistance(distance));
        return super.shouldRenderAtSqrDistance(distance);
    }

    public boolean shouldRender() {
        return  doFactory(factoryNotNull -> factoryNotNull.getProductFunction().shouldRender());
    }

    public void reloadData() {
        setUp(true);
    }

    @Override
    public void tick() {
        super.tick();
        if (!haveSetup) {
            setUp(false);
        }
        doFactory(factoryNotNull -> {
            {
                if (! renderInitiated && level().isClientSide) {
                    factoryNotNull
                            .getProductFunction()
                            .getFL()
                            .requestMountComponents(thisRideable);
                    renderInitiated = true;
                }

                factoryNotNull.getProductFunction().tick();
            }
        });

    }

    @Override
    public void kill() {
        doFactory(factoryNotNull -> {
            factoryNotNull.getProductFunction().kill();
        });
        for (Entity entity : getPassengers().stream().toList()) {
            entity.kill();
        }
        super.kill();
    }

    @Override
    protected void positionRider(Entity passenger, MoveFunction callback) {
        boolean hasSet = false;
        if (passenger instanceof ComponentEntity componentEntity) {
            Quaternionf totalRotation =  factory.getProductFunction().getFL().totalRotation;
//            componentEntity.setRotation(RotateWith.translateRotation(totalRotation));
            ComponentFL componentFL = componentEntity.getComponentFL();
            if (componentFL != null) {
                componentFL.setVehicle(this);
                Entity everyPassenger = componentEntity.getFirstPassenger();
                if (everyPassenger != null){
                    RotateWith.rotateEntity(everyPassenger, totalRotation);
                }
                Vec3 pos = componentFL.getRelativePosition();
                double eyeH = componentFL instanceof SeatFL ? 1.6200000047683716 : 0;
                Vec3 resultRelativePos = RotateWith.rotatePoint(componentFL.pivotX()+pos.x, componentFL.pivotY()+pos.y+eyeH, componentFL.pivotZ()+pos.z, totalRotation);
                resultRelativePos = new Vec3(resultRelativePos.x, resultRelativePos.y-eyeH, resultRelativePos.z);
                callback.accept(componentEntity, this.position().x+resultRelativePos.x, this.position().y+resultRelativePos.y, this.position().z+resultRelativePos.z);
                hasSet = true;
            }

        }
        if (!hasSet) {
            super.positionRider(passenger, callback);
        }


    }

    @Override
    public boolean canRiderInteract() {
        return true;
    }

    @Override
    public boolean canBeHitByProjectile() {
        return true;
    }
    @Override
    public boolean isAttackable() {
        return true; // 允许实体被攻击/交互
    }

    @Override
    public boolean isPickable() {
        return true; // 允许实体被选中
    }

    @Override
    public @NotNull InteractionResult interact(Player player, InteractionHand hand) {
        doFactory((factoryNotNull -> factoryNotNull.getProductFunction().interact(player, hand)));
        return super.interact(player, hand);
    }

    @Override
    protected void defineSynchedData() {
        this.entityData.define(factoryName,"");
    }

    @Override
    protected void readAdditionalSaveData(CompoundTag pCompound) {
        if (pCompound.contains("factoryName")) {
            this.entityData.set(factoryName, pCompound.getString("factoryName"));
        }
    }

    @Override
    protected void addAdditionalSaveData(CompoundTag pCompound) {
        pCompound.putString("factoryName", this.entityData.get(factoryName));
    }

    @Override
    public CompoundTag serverReceiveAndSending(CompoundTag serverOriginNbt, ServerPlayer executingPlayer, ACHeliPacketType packetType) {
        if (factory != null) {
            return factory.getProductFunction().serverReceiveAndSending(serverOriginNbt, executingPlayer, packetType);
        }
        return null;
    }

    @Override
    public void clientReceive(CompoundTag receivedNbt, boolean fromSelf, ACHeliPacketType packetType) {
        if (factory != null) {
            factory.getProductFunction().clientReceive(receivedNbt, fromSelf, packetType);
        }
    }

    @Override
    public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {

    }

    @Override
    public AnimatableInstanceCache getAnimatableInstanceCache() {
        return geoCache;
    }

    @Override
    public double getTick(Object object) {
        return 0;
    }


    public String getFactoryName() {
        return this.entityData.get(factoryName);
    }
}
